<template>
    <div class="validate-input-container pb-3">
        <!-- 这里的$attrs属性是将非 prop attribute 应用于 input / textarea元素 -->
        <input 
          v-if="tag !== 'textarea'"
          class="from-control"
          :class="{'is-invalid':inputRef.error}"
          @blur="validateInput"
          v-model="inputRef.val"
          v-bind="$attrs"
        >
        <textarea 
          v-else
          class="from-control"
          :class="{'is-invalid':inputRef.error}"
          @blur="validateInput"
          v-model="inputRef.val"
          v-bind="$attrs"
        >
        </textarea>
        <!-- 下面是红色的错误提示消息，如果inputRef.error为true证明有错误，直接输出Login.vue传过来的规则中定义好的出错提示信息 -->
        <span v-if="inputRef.error" class="invalid-feedback">{{inputRef.message}}</span>
    </div>
</template>

<script lang="ts">
import {defineComponent,reactive,PropType,onMounted,watch, computed} from 'vue'
import {emitter} from './ValidateForm.vue'
const emailReg = /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
const password = /^[a-zA-Z0-9]+$/
interface RuleProp{ //分别定义验证规则的类型，出错提示信息以及验证函数
    type:'required' | 'email' | 'password' | 'custom';
    message:string;
    validator?:()=>boolean;
}
export type RulesProp=RuleProp[]
export type TagType='input' | 'textarea'
export default defineComponent({    //此组件的逻辑在于对一个表单进行验证
    props:{
        rules:Array as PropType<RulesProp>, //正则表达式验证规则
        modelValue:String,  //Vue3中的v-modal的使用
        tag:{
            type:String as PropType<TagType>,
            default:'input'
        }
    },
    inheritAttrs:false, //禁止根元素继承非 prop attribute 
    setup(props,context){
        const inputRef = reactive({ //定义为响应式，val改变的时候页面也会根据值的改变而调整
            val:computed({  //定义为computed属性，每次里面的值改变时，就重新计算computed里面的值
                get:()=>props.modelValue || '', //setup里面不能用
                set:val=>{
                    context.emit('update:modelValue',val)   //Vue3中的v-modal的使用
                }
            }),
            error:false,
            message:''
        })
        const validateInput = ()=>{ //  验证规则函数，当鼠标离开输入框执行此函数
            if(props.rules){
                //every()方法，针对数组中的每一个元素进行比对，只要有一个元素比对结果为false则返回false
                //反之要所有的元素比对结果为true才为true
                const allPassed = props.rules.every(rule=>{ //检测输入的内容是否全部满足输入框规则的所有条件(一个输入框会有多个条件约束)
                    let passed = true   //默认为true，就是说输入的格式正确
                    inputRef.message = rule.message
                    switch(rule.type){
                        case 'required':
                            passed = (inputRef.val.trim() !== '')
                            break
                        case 'email':
                            passed = emailReg.test(inputRef.val)
                            break
                        case 'password':
                            passed = password.test(inputRef.val)
                            break
                        case 'custom':
                            passed = rule.validator?rule.validator():true   //确认密码时候会用
                            break
                        default:
                            break
                    }
                    return passed
                })
                inputRef.error = !allPassed //这个输入框中所有的规则都通过了，则allPassed为true
                return allPassed
            }
            return true //如果这个输入框没有任何验证规则，这说明用户填什么都可以，所以直接返回true
        }
        onMounted(()=>{ //相当于Vue2的mounted的函数，已经将内存中的模板挂载到了页面上
            emitter.emit('form-item-created',validateInput) //将本组件的validateInput验证表单方法发送给validateForm组件中的emitter.on()接收
        })
        return {
            inputRef,
            validateInput
        }
    }
})
</script>
